VERSION 1.0 CLASS
BEGIN
  MultiUse = -1  'True
  Persistable = 0  'NotPersistable
  DataBindingBehavior = 0  'vbNone
  DataSourceBehavior  = 0  'vbNone
  MTSTransactionMode  = 0  'NotAnMTSObject
END
Attribute VB_Name = "WaveInRecorder"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = True
Attribute VB_PredeclaredId = False
Attribute VB_Exposed = False
Option Explicit

' WaveInRecorder (VB 6)
'
' Records audio signal from WaveIn.
' Mixer line to record from can be selected,
' its volume can be changed.
' Buffercount/size can be modified.
' Uses In-Class subclassing by Paul Caton (PSC).

Private Declare Function GetModuleHandleA Lib "kernel32" ( _
    ByVal lpModuleName As String _
) As Long

Private Declare Function GetProcAddress Lib "kernel32" ( _
    ByVal hModule As Long, _
    ByVal lpProcName As String _
) As Long

Private Declare Function IsBadReadPtr Lib "kernel32" ( _
    ptr As Any, _
    ByVal ucb As Long _
) As Long

Private Declare Function IsBadCodePtr Lib "kernel32" ( _
    ByVal lpfn As Long _
) As Long

Private Declare Function GetWindowThreadProcessId Lib "user32" ( _
    ByVal hWnd As Long, _
    lpdwProcessId As Long _
) As Long

Private Declare Function GetCurrentProcessId Lib "kernel32" ( _
) As Long

Private Declare Function IsWindow Lib "user32" ( _
    ByVal hWnd As Long _
) As Long

Private Declare Function CallWindowProcA Lib "user32" ( _
    ByVal lpPrevWndFunc As Long, _
    ByVal hWnd As Long, _
    ByVal Msg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long _
) As Long

Private Declare Function CreateWindowEx Lib "user32" _
Alias "CreateWindowExA" ( _
    ByVal dwExStyle As Long, _
    ByVal lpClassName As String, _
    ByVal lpWindowName As String, _
    ByVal dwStyle As Long, _
    ByVal x As Long, _
    ByVal y As Long, _
    ByVal nWidth As Long, _
    ByVal nHeight As Long, _
    ByVal hWndParent As Long, _
    ByVal hMenu As Long, _
    ByVal hInstance As Long, _
    ByVal lpParam As Long _
) As Long

Private Declare Function DestroyWindow Lib "user32" ( _
    ByVal hWnd As Long _
) As Long

Private Declare Sub ZeroMem Lib "kernel32.dll" _
Alias "RtlZeroMemory" ( _
    pDst As Any, _
    ByVal cBytes As Long _
)

Private Declare Function VirtualFree Lib "kernel32" ( _
    ByVal lpAddress As Long, _
    ByVal dwSize As Long, _
    ByVal dwFreeType As Long _
) As Long

Private Declare Function VirtualAlloc Lib "kernel32" ( _
    ByVal lpAddress As Long, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long _
) As Long

Private Declare Function GlobalUnlock Lib "kernel32" ( _
    ByVal hMem As Long _
) As Long

Private Declare Function GlobalAlloc Lib "kernel32" ( _
    ByVal wFlags As GMEMFlags, _
    ByVal dwBytes As Long _
) As Long

Private Declare Function GlobalFree Lib "kernel32" ( _
    ByVal hMem As Long _
) As Long

Private Declare Function GlobalLock Lib "kernel32" ( _
    ByVal hMem As Long _
) As Long

Private Declare Function SetWindowLong Lib "user32" _
Alias "SetWindowLongA" ( _
    ByVal hWnd As Long, _
    ByVal nIndex As Long, _
    ByVal dwNewLong As Long _
) As Long

Private Declare Sub CpyMem Lib "kernel32" _
Alias "RtlMoveMemory" ( _
    pDst As Any, _
    pSrc As Any, _
    ByVal cBytes As Long _
)

Private Declare Function waveInAddBuffer Lib "winmm" ( _
    ByVal hwi As Long, _
    pwh As Any, _
    ByVal cbwh As Long _
) As Long

Private Declare Function waveInClose Lib "winmm" ( _
    ByVal hwi As Long _
) As Long

Private Declare Function waveInGetDevCaps Lib "winmm" _
Alias "waveInGetDevCapsA" ( _
    ByVal hwi As Long, _
    pwic As Any, _
    ByVal cbwic As Long _
) As Long

Private Declare Function waveInGetErrorText Lib "winmm" _
Alias "waveInGetErrorTextA" ( _
    ByVal mmrError As Long, _
    ByVal pszText As String, _
    ByVal cchText As Long _
) As Long

Private Declare Function waveInGetID Lib "winmm" ( _
    ByVal hwi As Long, _
    puDeviceID As Long _
) As Long

Private Declare Function waveInGetNumDevs Lib "winmm" ( _
) As Long

Private Declare Function waveInGetPosition Lib "winmm" ( _
    ByVal hwi As Long, _
    pmmt As Any, _
    ByVal cbmmt As Long _
) As Long

Private Declare Function waveInMessage Lib "winmm" ( _
    ByVal deviceid As Long, _
    ByVal uMsg As Long, _
    ByVal dwParam1 As Long, _
    ByVal dwParam2 As Long _
) As Long

Private Declare Function waveInOpen Lib "winmm" ( _
    phwi As Long, _
    ByVal uDeviceID As Long, _
    pwfx As Any, _
    ByVal dwCallback As Long, _
    ByVal dwCallbackInstance As Long, _
    ByVal fdwOpen As Long _
) As Long

Private Declare Function waveInPrepareHeader Lib "winmm" ( _
    ByVal hwi As Long, _
    pwh As Any, _
    ByVal cbwh As Long _
) As Long

Private Declare Function waveInUnprepareHeader Lib "winmm.dll" ( _
    ByVal hWaveIn As Long, _
    lpWaveInHdr As Any, _
    ByVal uSize As Long _
) As Long

Private Declare Function waveInReset Lib "winmm" ( _
    ByVal hwi As Long _
) As Long

Private Declare Function waveInStart Lib "winmm" ( _
    ByVal hwi As Long _
) As Long

Private Declare Function waveInStop Lib "winmm" ( _
    ByVal hwi As Long _
) As Long

Private Declare Function mixerClose Lib "winmm" ( _
    ByVal hmx As Long _
) As Long

Private Declare Function mixerOpen Lib "winmm" ( _
    phmx As Long, _
    ByVal uMxId As Long, _
    ByVal dwCallback As Long, _
    ByVal dwInstance As Long, _
    ByVal fdwOpen As Long _
) As Long

Private Declare Function mixerGetControlDetails Lib "winmm" _
Alias "mixerGetControlDetailsA" ( _
    ByVal hmxobj As Long, _
    pmxcd As MIXERCONTROLDETAILS, _
    ByVal fdwDetails As Long _
) As Long

Private Declare Function mixerGetLineControls Lib "winmm" _
Alias "mixerGetLineControlsA" ( _
    ByVal hmxobj As Long, _
    pmxlc As MIXERLINECONTROLS, _
    ByVal fdwControls As Long _
) As Long

Private Declare Function mixerGetLineInfo Lib "winmm" _
Alias "mixerGetLineInfoA" ( _
    ByVal hmxobj As Long, _
    pmxl As MIXERLINE, _
    ByVal fdwInfo As Long _
) As Long

Private Declare Function mixerSetControlDetails Lib "winmm" ( _
    ByVal hmxobj As Long, _
    pmxcd As MIXERCONTROLDETAILS, _
    ByVal fdwDetails As Long _
) As Long

Private Declare Function mixerGetDevCaps Lib "winmm" _
Alias "mixerGetDevCapsA" ( _
    ByVal uMxId As Long, _
    pmxcaps As MIXERCAPS, _
    ByVal cbmxcaps As Long _
) As Long

' of course there are a lot more line ids
Public Enum MIXER_RECORDING_LINES
    MIXERLINE_ANALOG = &H100A&
    MIXERLINE_AUXILIARY = &H1009&
    MIXERLINE_COMPACTDISC = &H1005&
    MIXERLINE_DIGITAL = &H1001&
    MIXERLINE_LINE = &H1002&
    MIXERLINE_MICROPHONE = &H1003&
    MIXERLINE_PCSPEAKER = &H1007&
    MIXERLINE_SYNTHESIZER = &H1004&
    MIXERLINE_TELEPHONE = &H1006&
    MIXERLINE_UNDEFINED = &H1000&
    MIXERLINE_WAVEOUT = &H1008&
End Enum

Private Enum GMEMFlags
    GMEM_FIXED = &H0
    GMEM_MOVEABLE = &H2
    GMEM_ZEROINIT = &H40
End Enum

' cSelfSub stuff
Private Enum eMsgWhen                               ' When to callback
    MSG_BEFORE = 1                                  ' Callback before the original WndProc
    MSG_AFTER = 2                                   ' Callback after the original WndProc
    MSG_BEFORE_AFTER = MSG_BEFORE Or MSG_AFTER      ' Callback before and after the original WndProc
End Enum

Private Const ALL_MESSAGES  As Long = -1            ' All messages callback
Private Const MSG_ENTRIES   As Long = 32            ' Number of msg table entries
Private Const WNDPROC_OFF   As Long = &H38          ' Thunk offset to the WndProc execution address
Private Const GWL_WNDPROC   As Long = -4            ' SetWindowsLong WndProc index
Private Const IDX_SHUTDOWN  As Long = 1             ' Thunk data index of the shutdown flag
Private Const IDX_HWND      As Long = 2             ' Thunk data index of the subclassed hWnd
Private Const IDX_WNDPROC   As Long = 9             ' Thunk data index of the original WndProc
Private Const IDX_BTABLE    As Long = 11            ' Thunk data index of the Before table
Private Const IDX_ATABLE    As Long = 12            ' Thunk data index of the After table
Private Const IDX_PARM_USER As Long = 13            ' Thunk data index of the User-defined callback parameter data index

Private z_ScMem             As Long                 ' Thunk base address
Private z_Sc(64)            As Long                 ' Thunk machine-code initialised here
Private z_Funk              As Collection           ' hWnd/thunk-address collection
' end cSelfSub stuff

Private Const WAVE_FORMAT_PCM                           As Long = 1&

Private Const MAXPNAMELEN                               As Long = 32&

Private Const MIXER_GETCONTROLDETAILSF_LISTTEXT         As Long = &H1&
Private Const MIXER_GETCONTROLDETAILSF_VALUE            As Long = &H0&

Private Const MIXER_GETLINECONTROLSF_ONEBYTYPE          As Long = &H2&
    
Private Const MIXER_GETLINEINFOF_COMPONENTTYPE          As Long = &H3&
Private Const MIXER_GETLINEINFOF_LINEID                 As Long = &H2&
Private Const MIXER_GETLINEINFOF_SOURCE                 As Long = &H1&
Private Const MIXER_GETLINEINFOF_DESTINATION            As Long = &H0&

Private Const MIXER_LONG_NAME_CHARS                     As Long = 64
Private Const MIXER_SHORT_NAME_CHARS                    As Long = 16

Private Const MIXERCONTROL_CONTROLTYPE_VOLUME           As Long = &H50030001
Private Const MIXERCONTROL_CONTROLTYPE_MUTE             As Long = &H20010002

Private Const MIXER_SETCONTROLDETAILSF_VALUE            As Long = &H0&

Private Const MIXER_OBJECTF_WAVEIN                      As Long = &H20000000

Private Const MIXERCONTROL_CT_UNITS_BOOLEAN             As Long = &H10000
Private Const MIXERCONTROL_CT_SC_LIST_MULTIPLE          As Long = &H1000000
Private Const MIXERCONTROL_CT_SC_LIST_SINGLE            As Long = 0&
Private Const MIXERCONTROL_CT_CLASS_LIST                As Long = &H70000000

Private Const MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT   As Long = (MIXERCONTROL_CT_CLASS_LIST Or MIXERCONTROL_CT_SC_LIST_MULTIPLE Or MIXERCONTROL_CT_UNITS_BOOLEAN)
Private Const MIXERCONTROL_CONTROLTYPE_SINGLESELECT     As Long = (MIXERCONTROL_CT_CLASS_LIST Or MIXERCONTROL_CT_SC_LIST_SINGLE Or MIXERCONTROL_CT_UNITS_BOOLEAN)

Private Const MIXERCONTROL_CONTROLTYPE_MIXER            As Long = (MIXERCONTROL_CONTROLTYPE_MULTIPLESELECT + 1)
Private Const MIXERCONTROL_CONTROLTYPE_MUX              As Long = (MIXERCONTROL_CONTROLTYPE_SINGLESELECT + 1)

Private Const MIXERLINE_COMPONENTTYPE_DST_WAVEIN        As Long = &H7&

Private Const CALLBACK_WINDOW                           As Long = &H10000

Private Const MM_WIM_OPEN                               As Long = &H3BE
Private Const MM_WIM_CLOSE                              As Long = &H3BF
Private Const MM_WIM_DATA                               As Long = &H3C0

Private Const WM_DESTROY                                As Long = &H2&
Private Const MMSYSERR_NOERROR                          As Long = 0&

Private Type MIXERCONTROLDETAILS_LISTTEXT
    dwParam1                                    As Long
    dwParam2                                    As Long
    szName                                      As Long
End Type

Private Type MIXERCONTROL
    cbStruct                                    As Long
    dwControlID                                 As Long
    dwControlType                               As Long
    fdwControl                                  As Long
    cMultipleItems                              As Long
    szShortName(MIXER_SHORT_NAME_CHARS / 2 - 1) As Integer
    szName(MIXER_LONG_NAME_CHARS / 2 - 1)       As Integer
    Bounds(5)                                   As Long
    Metrics(5)                                  As Long
End Type

Private Type MIXERCONTROLDETAILS
    cbStruct                                    As Long
    dwControlID                                 As Long
    cChannels                                   As Long
    item                                        As Long
    cbDetails                                   As Long
    paDetails                                   As Long
End Type

Private Type Target
    dwType                                      As Long
    dwDeviceID                                  As Long
    wMid                                        As Integer
    wPid                                        As Integer
    vDriverVersion                              As Long
    szPname                                     As String * MAXPNAMELEN
End Type

Private Type MIXERLINE
    cbStruct                                    As Long
    dwDestination                               As Long
    dwSource                                    As Long
    dwLineID                                    As Long
    fdwLine                                     As Long
    dwUser                                      As Long
    dwComponentType                             As Long
    cChannels                                   As Long
    cConnections                                As Long
    cControls                                   As Long
    szShortName                                 As String * MIXER_SHORT_NAME_CHARS
    szName                                      As String * MIXER_LONG_NAME_CHARS
    tTarget                                     As Target
End Type

Private Type MIXERLINECONTROLS
    cbStruct                                    As Long
    dwLineID                                    As Long
    dwControl                                   As Long
    cControls                                   As Long
    cbmxctrl                                    As Long
    pamxctrl                                    As Long
End Type

Private Type MIXERCAPS
    wMid                                        As Integer
    wPid                                        As Integer
    vDriverVersion                              As Long
    szPname                                     As String * 32
    fdwSupport                                  As Long
    cDestinations                               As Long
End Type

Private Type MIXERCONTROLDETAILS_BOOLEAN
     fValue                                     As Long
End Type

Private Type volume_stereo
    L                                           As Long
    R                                           As Long
End Type

Private Type WAVEFORMATEX
    wFormatTag                                  As Integer
    nChannels                                   As Integer
    nSamplesPerSec                              As Long
    nAvgBytesPerSec                             As Long
    nBlockAlign                                 As Integer
    wBitsPerSample                              As Integer
    cbSize                                      As Integer
End Type

Private Type WAVEHDR
    lpData                                      As Long
    dwBufferLen                                 As Long
    dwBytesRec                                  As Long
    dwUser                                      As Long
    dwFlags                                     As Long
    dwLoops                                     As Long
    lpNext                                      As Long
    reserved                                    As Long
End Type

Private Type WAVEFORMAT
    wFormatTag                                  As Integer
    nChannels                                   As Integer
    nSamplesPerSec                              As Long
    nAvgBytesPerSec                             As Long
    nBlockAlign                                 As Integer
End Type

Private Type WAVEINCAPS
    wMid                                        As Integer
    wPid                                        As Integer
    vDriverVer                                  As Long
    szPname                                     As String * MAXPNAMELEN
    dwFormats                                   As Long
    wChannels                                   As Integer
    wReserved1                                  As Integer
End Type

Private Type MMTIME
    wType                                       As Long
    U                                           As Long
End Type

Private Type WaveInBuffer
    hdr                                         As WAVEHDR
    intBuffer()                                 As Integer
    pMem                                        As Long
End Type

Private lngCurDev                               As Long
Private lngBufSize                              As Long
Private lngBufCnt                               As Long

Private udtBuffers()                            As WaveInBuffer

Private lngPrevProc                             As Long
Private lngHwnd                                 As Long

Private hWaveIn                                 As Long
Private hMixer                                  As Long

Public Event GotData( _
    intBuffer() As Integer, _
    lngLen As Long _
)

Public Property Get IsRecording( _
) As Boolean

    IsRecording = hWaveIn <> 0
End Property

' http://www.ureader.com/message/1359669.aspx
Private Function SetMixerLine2( _
    ByVal devid As Long, _
    ByVal index As Long _
) As Boolean

    Dim retval      As Long
    Dim terr        As Long
    Dim mxl         As MIXERLINE
    Dim controls    As MIXERLINECONTROLS
    Dim control     As MIXERCONTROL
    Dim hControl    As Long
    Dim pControl    As Long
    Dim cd          As MIXERCONTROLDETAILS
    Dim hr          As Long
    Dim i           As Long
    Dim c           As Long
    Dim j           As Long
    Dim lv          As MIXERCONTROLDETAILS_BOOLEAN
    Dim hLV         As Long
    Dim pLV         As Long

    mxl.cbStruct = Len(mxl)
    mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN
    hr = mixerGetLineInfo(devid, mxl, MIXER_GETLINEINFOF_COMPONENTTYPE)
    hr = mixerGetLineInfo(devid, mxl, MIXER_GETLINEINFOF_DESTINATION)

    If (hr <> 0) Then Exit Function

    For i = 0 To mxl.dwDestination - 1
        controls.cbStruct = Len(controls)
        controls.dwLineID = mxl.dwLineID
        controls.cControls = mxl.cControls
        controls.cbmxctrl = Len(control)

        hControl = GlobalAlloc(GMEM_ZEROINIT, Len(control) * controls.cControls)
        pControl = GlobalLock(hControl)

        controls.pamxctrl = pControl
        controls.dwControl = MIXERCONTROL_CONTROLTYPE_MUX

        terr = mixerGetLineControls(devid, controls, MIXER_GETLINECONTROLSF_ONEBYTYPE)
        If terr <> 0 Then Exit Function
        CpyMem control, ByVal pControl, Len(control)
        If index > control.cMultipleItems Then
            GoTo SkipItem
        End If

        For c = 0 To controls.cControls - 1
            CpyMem control, ByVal pControl + Len(control) * c, Len(control)
            If (MIXERCONTROL_CONTROLTYPE_MUX = (MIXERCONTROL_CONTROLTYPE_MUX And control.dwControlType)) Then
                cd.cbStruct = Len(cd)
                cd.dwControlID = control.dwControlID
                cd.cChannels = 1
                cd.item = control.cMultipleItems
                cd.cbDetails = Len(lv)

                hLV = GlobalAlloc(GMEM_ZEROINIT, cd.cChannels * cd.item * cd.cbDetails)
                pLV = GlobalLock(hLV)
                
                cd.paDetails = pLV

                terr = mixerGetControlDetails(devid, cd, MIXER_GETCONTROLDETAILSF_VALUE)

                For j = 0 To cd.item - 1
                    CpyMem lv, ByVal pLV + Len(lv) * j, Len(lv)
                    If lv.fValue Then retval = i
                    lv.fValue = Abs(CBool(j = index))
                    CpyMem ByVal pLV + Len(lv) * j, lv, Len(lv)
                Next

                terr = mixerSetControlDetails(devid, cd, MIXER_SETCONTROLDETAILSF_VALUE)

                GlobalUnlock hLV
                GlobalFree hLV
            End If
        Next

SkipItem:
        GlobalUnlock hControl
        GlobalFree hControl
    Next

    SetMixerLine2 = True
End Function

' http://www.ureader.com/message/1359669.aspx
Private Function GetMixerLine2( _
    ByVal devid As Long _
) As Long

    Dim retval      As Long
    Dim terr        As Long
    Dim mxl         As MIXERLINE
    Dim controls    As MIXERLINECONTROLS
    Dim control     As MIXERCONTROL
    Dim hControl    As Long
    Dim pControl    As Long
    Dim cd          As MIXERCONTROLDETAILS
    Dim hr          As Long
    Dim i           As Long
    Dim c           As Long
    Dim j           As Long
    Dim lv          As MIXERCONTROLDETAILS_BOOLEAN
    Dim hLV         As Long
    Dim pLV         As Long

    mxl.cbStruct = Len(mxl)
    mxl.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN
    hr = mixerGetLineInfo(devid, mxl, MIXER_GETLINEINFOF_COMPONENTTYPE)
    hr = mixerGetLineInfo(devid, mxl, MIXER_GETLINEINFOF_DESTINATION)

    If (hr <> 0) Then Exit Function

    For i = 0 To mxl.dwDestination - 1
        controls.cbStruct = Len(controls)
        controls.dwLineID = mxl.dwLineID
        controls.cControls = mxl.cControls
        controls.cbmxctrl = Len(control)

        hControl = GlobalAlloc(GMEM_ZEROINIT, Len(control) * controls.cControls)
        pControl = GlobalLock(hControl)

        controls.pamxctrl = pControl
        controls.dwControl = MIXERCONTROL_CONTROLTYPE_MUX

        terr = mixerGetLineControls(devid, controls, MIXER_GETLINECONTROLSF_ONEBYTYPE)
        If terr <> 0 Then Exit Function

        For c = 0 To controls.cControls - 1
            CpyMem control, ByVal pControl + Len(control) * c, Len(control)
            If (MIXERCONTROL_CONTROLTYPE_MUX = (MIXERCONTROL_CONTROLTYPE_MUX And control.dwControlType)) Then
                cd.cbStruct = Len(cd)
                cd.dwControlID = control.dwControlID
                cd.cChannels = 1
                cd.item = control.cMultipleItems
                cd.cbDetails = Len(lv)

                hLV = GlobalAlloc(GMEM_ZEROINIT, cd.cChannels * cd.item * cd.cbDetails)
                pLV = GlobalLock(hLV)
                
                cd.paDetails = pLV

                terr = mixerGetControlDetails(devid, cd, MIXER_GETCONTROLDETAILSF_VALUE)

                For j = 0 To cd.item - 1
                    CpyMem lv, ByVal pLV + Len(lv) * j, Len(lv)
                    If lv.fValue Then retval = j
                Next

                GlobalUnlock hLV
                GlobalFree hLV
            End If
        Next

SkipItem:
        GlobalUnlock hControl
        GlobalFree hControl
    Next

    GetMixerLine2 = retval
End Function

Public Function StopRecord( _
) As Boolean

    Dim i   As Long
    Dim res As Long

    If hWaveIn <> 0 Then
        ' make sure all buffers are returned to us
        res = waveInStop(hWaveIn)
        If res <> 0 Then Debug.Print "waveInStop: " & res
        res = waveInReset(hWaveIn)
        If res <> 0 Then Debug.Print "waveInReset: " & res

        ' destroy all buffers
        For i = 0 To lngBufCnt - 1
            res = waveInUnprepareHeader(hWaveIn, _
                                  udtBuffers(i).hdr, _
                                  Len(udtBuffers(i).hdr))

            If res <> 0 Then Debug.Print "waveInUnprep " & i & ": " & res
        Next

        res = waveInClose(hWaveIn)
        If res <> 0 Then Debug.Print "waveInClose: " & res

        hWaveIn = 0
    End If

    DeinitWaveInWnd

    StopRecord = True
End Function

Public Function StartRecord( _
    ByVal samplerate As Long, _
    ByVal Channels As Integer _
) As Boolean

    Dim udtWFX  As WAVEFORMATEX
    Dim res     As Long
    Dim i       As Long
    Dim j       As Long

    ReDim udtBuffers(lngBufCnt - 1) As WaveInBuffer

    InitWaveInWnd

    With udtWFX
        .wFormatTag = WAVE_FORMAT_PCM
        .nSamplesPerSec = samplerate
        .nChannels = Channels
        .wBitsPerSample = 16
        .nBlockAlign = Channels * (.wBitsPerSample / 8)
        .nAvgBytesPerSec = .nBlockAlign * .nSamplesPerSec
        .cbSize = 0
    End With

    res = waveInOpen(hWaveIn, lngCurDev, udtWFX, lngHwnd, 0, CALLBACK_WINDOW)
    If res <> MMSYSERR_NOERROR Then
        DeinitWaveInWnd
        Exit Function
    End If

    ' prepare headers/buffers
    For i = 0 To lngBufCnt - 1
        With udtBuffers(i)
            ReDim .intBuffer(lngBufSize / 2 - 1) As Integer
            .pMem = VarPtr(.intBuffer(0))
            .hdr.dwBufferLen = lngBufSize
            .hdr.lpData = .pMem
            .hdr.dwUser = i

            res = waveInPrepareHeader(hWaveIn, .hdr, Len(.hdr))
            If res <> MMSYSERR_NOERROR Then
                ' on error unprepare all prepared headers
                For j = (i - 1) To 0 Step -1
                    waveInUnprepareHeader hWaveIn, .hdr, Len(.hdr)
                Next

                waveInClose hWaveIn
                hWaveIn = 0

                DeinitWaveInWnd

                Exit Function
            End If
        End With
    Next

    res = waveInStart(hWaveIn)
    If res <> MMSYSERR_NOERROR Then
        For i = 0 To lngBufCnt - 1
            waveInUnprepareHeader hWaveIn, _
                                  udtBuffers(i).hdr, _
                                  Len(udtBuffers(i).hdr)
        Next

        waveInClose hWaveIn
        hWaveIn = 0

        DeinitWaveInWnd

        Exit Function
    End If

    For i = 0 To lngBufCnt - 1
        waveInAddBuffer hWaveIn, _
                        udtBuffers(i).hdr, _
                        Len(udtBuffers(i).hdr)
    Next

    StartRecord = True
End Function

' number of buffers to be used for recording
Public Property Get BufferCount( _
) As Long

    BufferCount = lngBufCnt
End Property

Public Property Let BufferCount( _
    ByVal index As Long _
)

    lngBufCnt = index
End Property

' size of a buffer in bytes
' (must be multiple of 2 because we use 16 bit integers)
Public Property Get BufferSize( _
) As Long

    BufferSize = lngBufSize
End Property

Public Property Let BufferSize( _
    ByVal bytes As Long _
)

    lngBufSize = bytes
End Property

Public Property Get DeviceCount( _
) As Long

    DeviceCount = waveInGetNumDevs()
End Property

Public Property Get DeviceName( _
    ByVal index As Long _
) As String

    Dim udtInfo As WAVEINCAPS
    Dim strName As String

    waveInGetDevCaps index, udtInfo, Len(udtInfo)
    strName = udtInfo.szPname

    If InStr(strName, Chr$(0)) > 0 Then
        strName = Left$(strName, InStr(strName, Chr$(0)) - 1)
    End If

    DeviceName = udtInfo.szPname
End Property

Public Function SelectDevice( _
    ByVal index As Long _
) As Boolean

    If index < 0 Or index > DeviceCount - 1 Then
        Exit Function
    End If

    lngCurDev = -1

    If hMixer <> 0 Then
        mixerClose hMixer
        hMixer = 0
    End If

    mixerOpen hMixer, index, 0, 0, MIXER_OBJECTF_WAVEIN
    If hMixer = 0 Then Exit Function

    lngCurDev = index

    SelectDevice = True
End Function

Public Property Get MixerLineCount( _
) As Long

    Dim i   As Long

    If lngCurDev < 0 Then Exit Property

    For i = 0 To MixerDestinations(hMixer) - 1
        If MixerDestinationType(hMixer, i) = MIXERLINE_COMPONENTTYPE_DST_WAVEIN Then
            MixerLineCount = MixerDestinationConnections(hMixer, i)
            Exit For
        End If
    Next
End Property

Public Property Get MixerLineName( _
    ByVal index As Long _
) As String

    Dim i   As Long

    If lngCurDev < 0 Then Exit Property

    For i = 0 To MixerDestinations(hMixer) - 1
        If MixerDestinationType(hMixer, i) = MIXERLINE_COMPONENTTYPE_DST_WAVEIN Then
            MixerLineName = MixerConnectionName(hMixer, i, index)
            Exit For
        End If
    Next
End Property

Public Function SelectMixerLine( _
    ByVal index As Long _
) As Boolean

    If lngCurDev < 0 Then Exit Function

    SelectMixerLine = SetMixerLine2(hMixer, MixerLineCount - index - 1)
End Function

Public Property Get SelectedDevice( _
) As Long

    SelectedDevice = lngCurDev
End Property

Public Property Get SelectedMixerLine( _
) As Long

     SelectedMixerLine = MixerLineCount - GetMixerLine2(hMixer) - 1
End Property

Public Property Get MixerLineType( _
    Optional ByVal index As Long = -1 _
) As Long

    Dim i       As Long
    Dim lngLine As Long

    If index = -1 Then
        lngLine = SelectedMixerLine
    Else
        lngLine = index
    End If

    For i = 0 To MixerDestinations(hMixer) - 1
        If MixerDestinationType(hMixer, i) = MIXERLINE_COMPONENTTYPE_DST_WAVEIN Then
            MixerLineType = MixerConnectionType(hMixer, i, lngLine)
            Exit For
        End If
    Next
End Property

Public Property Get MixerLineVolume( _
) As Long

    Dim i       As Long
    Dim udtVol  As volume_stereo

    For i = 0 To MixerDestinations(hMixer) - 1
        If MixerDestinationType(hMixer, i) = MIXERLINE_COMPONENTTYPE_DST_WAVEIN Then
            udtVol = MixerConnectionVolume(hMixer, i, SelectedMixerLine)
            Exit For
        End If
    Next

    MixerLineVolume = udtVol.L
End Property

Public Property Let MixerLineVolume( _
    ByVal Volume As Long _
)

    Dim i       As Long
    Dim udtVol  As volume_stereo

    udtVol.L = Volume
    udtVol.R = Volume

    For i = 0 To MixerDestinations(hMixer) - 1
        If MixerDestinationType(hMixer, i) = MIXERLINE_COMPONENTTYPE_DST_WAVEIN Then
            MixerSetConnectionVolume hMixer, i, SelectedMixerLine, udtVol
            Exit For
        End If
    Next
End Property

' subclass the created fake window
Private Sub Attach( _
    ByVal hWnd As Long _
)

    lngHwnd = hWnd
    sc_Subclass lngHwnd
    sc_AddMsg lngHwnd, MM_WIM_DATA
End Sub

' remove our window proc
Private Sub Detach()
    If lngHwnd Then
        sc_UnSubclass lngHwnd
        lngHwnd = 0
    End If
End Sub

' waveIn API requires either a callback or a
' window to send messages to.
' As adding a buffer to the WaveIn Queue in a
' direct callback causes a dead lock, better
' use a fake window.
Private Sub InitWaveInWnd()
    lngHwnd = CreateWindowEx(0&, _
                             "STATIC", _
                             "WAVE_IN_WINDOW", _
                             0&, 0&, 0&, 0&, _
                             0&, 0&, 0&, _
                             App.hInstance, _
                             0&)

    Attach lngHwnd
End Sub

Private Sub DeinitWaveInWnd()
    Detach
    DestroyWindow lngHwnd: lngHwnd = 0: lngPrevProc = 0
End Sub

Private Sub Class_Initialize()
    lngBufCnt = 5
    lngBufSize = 10& * 1024&
    lngCurDev = -1
End Sub

Private Sub Class_Terminate()
    If IsRecording Then
        StopRecord
    End If

    If hMixer <> 0 Then
        mixerClose hMixer
    End If
End Sub

' /////////////////////////////////////////////////
' ////////// WINDOWS MIXER FUNCTIONS
' /////////////////////////////////////////////////

Private Property Get MixerConnectionType( _
    ByVal devid As Long, _
    ByVal destination As Long, _
    ByVal connection As Long _
) As Long

    Dim udtML   As MIXERLINE

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination
    udtML.dwSource = connection

    mixerGetLineInfo devid, udtML, MIXER_GETLINEINFOF_SOURCE

    MixerConnectionType = udtML.dwComponentType
End Property

Private Property Get MixerDestinations( _
    ByVal deviceid As Long _
) As Long

    Dim udtCaps As MIXERCAPS

    mixerGetDevCaps deviceid, udtCaps, Len(udtCaps)

    MixerDestinations = udtCaps.cDestinations
End Property

Private Property Get MixerConnectionName( _
    ByVal deviceid As Long, _
    ByVal destination As Long, _
    ByVal connection As Long _
) As String

    Dim udtML   As MIXERLINE

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination
    udtML.dwSource = connection

    mixerGetLineInfo deviceid, _
                     udtML, _
                     MIXER_GETLINEINFOF_SOURCE

    MixerConnectionName = udtML.szName
End Property

Private Property Get MixerDestinationConnections( _
    ByVal deviceid As Long, _
    ByVal destination As Long _
) As Long

    Dim udtML   As MIXERLINE

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination

    mixerGetLineInfo deviceid, _
                     udtML, _
                     MIXER_GETLINEINFOF_DESTINATION

    MixerDestinationConnections = udtML.cConnections
End Property

Private Property Get MixerDestinationType( _
    ByVal deviceid As Long, _
    ByVal destination As Long _
) As Long

    Dim udtML   As MIXERLINE

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination

    mixerGetLineInfo deviceid, _
                     udtML, _
                     MIXER_GETLINEINFOF_DESTINATION

    MixerDestinationType = udtML.dwComponentType
End Property

Private Sub MixerSetConnectionVolume( _
    ByVal deviceid As Long, _
    ByVal destination As Long, _
    ByVal connection As Long, _
    vol As volume_stereo _
)

    Dim udtML   As MIXERLINE
    Dim udtMCL  As MIXERCONTROLDETAILS
    Dim CtrlID  As Long

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination
    udtML.dwSource = connection

    mixerGetLineInfo deviceid, udtML, MIXER_GETLINEINFOF_SOURCE

    CtrlID = MixerGetControlID(deviceid, _
                               udtML.dwComponentType, _
                               MIXERCONTROL_CONTROLTYPE_VOLUME, _
                               udtML.dwLineID)

    With udtMCL
        .cbDetails = 4
        .cbStruct = Len(udtMCL)
        .cChannels = udtML.cChannels
        .dwControlID = CtrlID
        .item = 0
        .paDetails = VarPtr(vol)
    End With

    mixerSetControlDetails deviceid, _
                           udtMCL, _
                           MIXER_SETCONTROLDETAILSF_VALUE
End Sub

Private Property Get MixerConnectionVolume( _
    ByVal deviceid As Long, _
    ByVal destination As Long, _
    ByVal connection As Long _
) As volume_stereo

    Dim udtML   As MIXERLINE
    Dim udtMCL  As MIXERCONTROLDETAILS
    Dim udtVol  As volume_stereo
    Dim CtrlID  As Long

    udtML.cbStruct = Len(udtML)
    udtML.dwDestination = destination
    udtML.dwSource = connection

    mixerGetLineInfo deviceid, udtML, MIXER_GETLINEINFOF_SOURCE

    CtrlID = MixerGetControlID(deviceid, _
                               udtML.dwComponentType, _
                               MIXERCONTROL_CONTROLTYPE_VOLUME, _
                               udtML.dwLineID)

    With udtMCL
        .cbDetails = 4
        .cbStruct = Len(udtMCL)
        .cChannels = udtML.cChannels
        .dwControlID = CtrlID
        .item = 0
        .paDetails = VarPtr(udtVol)
    End With

    mixerGetControlDetails deviceid, _
                           udtMCL, _
                           MIXER_GETCONTROLDETAILSF_VALUE

    MixerConnectionVolume = udtVol
End Property

Private Function MixerGetControlID( _
    ByVal deviceid As Long, _
    ByVal ComponentType As Long, _
    ByVal ControlType As Long, _
    ByVal LineID As Long _
) As Long

    Dim hMem     As Long
    Dim MC       As MIXERCONTROL
    Dim MxrLine  As MIXERLINE
    Dim MLC      As MIXERLINECONTROLS

    MxrLine.cbStruct = Len(MxrLine)
    MxrLine.dwComponentType = ComponentType

    If mixerGetLineInfo(deviceid, _
                        MxrLine, _
                        MIXER_GETLINEINFOF_COMPONENTTYPE) = 0 Then

        MLC.cbStruct = Len(MLC)
        MLC.dwLineID = LineID
        MLC.dwControl = ControlType
        MLC.cControls = 1
        MLC.cbmxctrl = Len(MC)

        hMem = GlobalAlloc(&H40, Len(MC))
        If hMem = 0 Then Exit Function
        MLC.pamxctrl = GlobalLock(hMem)

        MC.cbStruct = Len(MC)

        If mixerGetLineControls(deviceid, _
                                MLC, _
                                MIXER_GETLINECONTROLSF_ONEBYTYPE) = 0 Then

            CpyMem MC, ByVal MLC.pamxctrl, Len(MC)
            MixerGetControlID = MC.dwControlID
        End If

        GlobalUnlock hMem
        GlobalFree hMem
    End If
End Function


'-SelfSub code------------------------------------------------------------------------------------
' by Paul Caton

Private Function sc_Subclass( _
    ByVal lng_hWnd As Long, _
    Optional ByVal lParamUser As Long = 0, _
    Optional ByVal nOrdinal As Long = 1, _
    Optional ByVal oCallback As Object = Nothing, _
    Optional ByVal bIdeSafety As Boolean = True _
) As Boolean 'Subclass the specified window handle

'*************************************************************************************************
'* lng_hWnd   - Handle of the window to subclass
'* lParamUser - Optional, user-defined callback parameter
'* nOrdinal   - Optional, ordinal index of the callback procedure. 1 = last private method, 2 = second last private method, etc.
'* oCallback  - Optional, the object that will receive the callback. If undefined, callbacks are sent to this object's instance
'* bIdeSafety - Optional, enable/disable IDE safety measures. NB: you should really only disable IDE safety in a UserControl for design-time subclassing
'*************************************************************************************************
Const CODE_LEN      As Long = 260                                           'Thunk length in bytes
Const MEM_LEN       As Long = CODE_LEN + (8 * (MSG_ENTRIES + 1))            'Bytes to allocate per thunk, data + code + msg tables
Const PAGE_RWX      As Long = &H40&                                         'Allocate executable memory
Const MEM_COMMIT    As Long = &H1000&                                       'Commit allocated memory
Const MEM_RELEASE   As Long = &H8000&                                       'Release allocated memory flag
Const IDX_EBMODE    As Long = 3                                             'Thunk data index of the EbMode function address
Const IDX_CWP       As Long = 4                                             'Thunk data index of the CallWindowProc function address
Const IDX_SWL       As Long = 5                                             'Thunk data index of the SetWindowsLong function address
Const IDX_FREE      As Long = 6                                             'Thunk data index of the VirtualFree function address
Const IDX_BADPTR    As Long = 7                                             'Thunk data index of the IsBadCodePtr function address
Const IDX_OWNER     As Long = 8                                             'Thunk data index of the Owner object's vTable address
Const IDX_CALLBACK  As Long = 10                                            'Thunk data index of the callback method address
Const IDX_EBX       As Long = 16                                            'Thunk code patch index of the thunk data
Const SUB_NAME      As String = "sc_Subclass"                               'This routine's name
  Dim nAddr         As Long
  Dim nID           As Long
  Dim nMyID         As Long
  
    If IsWindow(lng_hWnd) = 0 Then                                            'Ensure the window handle is valid
        zError SUB_NAME, "Invalid window handle"
        Exit Function
    End If

    nMyID = GetCurrentProcessId                                               'Get this process's ID
    GetWindowThreadProcessId lng_hWnd, nID                                    'Get the process ID associated with the window handle
    If nID <> nMyID Then                                                      'Ensure that the window handle doesn't belong to another process
        zError SUB_NAME, "Window handle belongs to another process"
        Exit Function
    End If
  
    If oCallback Is Nothing Then                                              'If the user hasn't specified the callback owner
        Set oCallback = Me                                                      'Then it is me
    End If
  
    nAddr = zAddressOf(oCallback, nOrdinal)                                   'Get the address of the specified ordinal method
    If nAddr = 0 Then                                                         'Ensure that we've found the ordinal method
        zError SUB_NAME, "Callback method not found"
        Exit Function
    End If
    
    If z_Funk Is Nothing Then                                                 'If this is the first time through, do the one-time initialization
        Set z_Funk = New Collection                                             'Create the hWnd/thunk-address collection
        z_Sc(14) = &HD231C031: z_Sc(15) = &HBBE58960: z_Sc(17) = &H4339F631: z_Sc(18) = &H4A21750C: z_Sc(19) = &HE82C7B8B: z_Sc(20) = &H74&: z_Sc(21) = &H75147539: z_Sc(22) = &H21E80F: z_Sc(23) = &HD2310000: z_Sc(24) = &HE8307B8B: z_Sc(25) = &H60&: z_Sc(26) = &H10C261: z_Sc(27) = &H830C53FF: z_Sc(28) = &HD77401F8: z_Sc(29) = &H2874C085: z_Sc(30) = &H2E8&: z_Sc(31) = &HFFE9EB00: z_Sc(32) = &H75FF3075: z_Sc(33) = &H2875FF2C: z_Sc(34) = &HFF2475FF: z_Sc(35) = &H3FF2473: z_Sc(36) = &H891053FF: z_Sc(37) = &HBFF1C45: z_Sc(38) = &H73396775: z_Sc(39) = &H58627404
        z_Sc(40) = &H6A2473FF: z_Sc(41) = &H873FFFC: z_Sc(42) = &H891453FF: z_Sc(43) = &H7589285D: z_Sc(44) = &H3045C72C: z_Sc(45) = &H8000&: z_Sc(46) = &H8920458B: z_Sc(47) = &H4589145D: z_Sc(48) = &HC4836124: z_Sc(49) = &H1862FF04: z_Sc(50) = &H35E30F8B: z_Sc(51) = &HA78C985: z_Sc(52) = &H8B04C783: z_Sc(53) = &HAFF22845: z_Sc(54) = &H73FF2775: z_Sc(55) = &H1C53FF28: z_Sc(56) = &H438D1F75: z_Sc(57) = &H144D8D34: z_Sc(58) = &H1C458D50: z_Sc(59) = &HFF3075FF: z_Sc(60) = &H75FF2C75: z_Sc(61) = &H873FF28: z_Sc(62) = &HFF525150: z_Sc(63) = &H53FF2073: z_Sc(64) = &HC328&

        z_Sc(IDX_CWP) = zFnAddr("user32", "CallWindowProcA")                    'Store CallWindowProc function address in the thunk data
        z_Sc(IDX_SWL) = zFnAddr("user32", "SetWindowLongA")                     'Store the SetWindowLong function address in the thunk data
        z_Sc(IDX_FREE) = zFnAddr("kerrrrrrrrrrrrrrrrr5FF2C75:Conta        z_Sc(Iu STBUnFF525150:z_Sc(60) = &H75F'eNaludtML.cCh= zFnAddr("     zError SUB_NAME, "Wia&H4fDzFnR     As LTDE1E, "Wia&H4fDzFnR     As LTDE1E, "Wia&H4fDzFnRl_Sc(60) = &H)W"Wia&Hi = 0 To MixerDe3FF: z_Sc(43) = &H7589285D: zDtB2,8rD&HFFia&H4fDzFB25) = &H60Fiaee created fake window
Private Sceated fak st25150: z_) =  If z_rnR     As LTDE1E, "Wia&H4fDzFnR     As LTDE1E, "Wia&H4fDzFnRl_Sor  LTDE1Property

Publi             As Long
    szName                             Sceated fak st2he callback F631: z_Sc(18)wtm hMem     As Long
    Dim MC                       S1E, "Wia&H4fDzFnR(0: z_Sc(17) =  method
1ng = 1ive the c collection
1ng       eaaaaaaaaaaaaaaaa colleclaaa   S6*MIf terr <> 0 I=t'on
1ng       eaau=_Sc(60) = &H75th

 pUuhing Then                                  mm MC       rsleclaaa   S6*MIf terr <> 0 I=t'on
1ng   _Sc(yID = GeM    mm MC       rslecl_Sc(20) = &H7Dim MC lAs Lyate 'Th    ac(yID = GeM    mm MC       rslecl_Sc(20) = &H7Dim MC lAs Lyate 'Th    ac(yIDpH75FF3075: z_Sc(=              mm M  ac(yIDpH75FF3     rslecl_ conShod not found"erslecl_Sc(20) = &H7Dim MC lAs Lyta&H4fiC   ,FCaWFlT
&H40, Len(MC))
        If                                     Dim MC lAs Lyate 'Th    ac(yID=l_Sc(20) = &H7DimWSc(e &H4589145D: z(yID=lllllllllllllllllllllllll) = n 0 I=t'on
1ng   _D = GeM    mm MC       rslec04
        z_Sc(40) =  l(= indeu
   = 0 To MinutionName = udtML.szName
E8lecl_          .szNameC             _Sc(fak st2he cnR(0            _Sc(NlWrfiC   ,FCaWFlT
&H40, Len(MC))
        If   iInC       rslecl_Sc(trolID(        () 0 I=t'on
1ng   _D = GeM    m_D = GeM    mm MC       rslec0tz(yID=lllllllllslecic:40, Len(MC))
Sc(43--------------lWrfiC   ,FCa

Private lngPrevProc                 either a call6ab RT
&ngPrevP   mm MCfunctio--------ate lak st2he cnR(0            _Scs LyW           sh    ac(l+ss tailxlfcactio------c0tz(yI         i(yIMj          _Scs LsDim MC lAs Lyate                   sh         &H7Dim MC lAsd fak st2he callback F631: z_Sc(18)wtm hMem     As Long
    Dim MC                       S1E, "Wia&H4fDzFnR(0: z_Sc(17) =  method
1ng = 1ive the c collection
1ng       eaaaaaaaaaaaaaaaa colleclaaa   S6*MIf terr <> 0 I=t'on
1ng       eaau=_Sc(60) = &H75th
Cn: a index of the S ina   S6*MIf terr <> 0 I=t'on
1ng       eaau=_Sc(60) = &H75th
      ehDT ( _
) Ashe IsH7DiT Ashe IsH7DiTr   33333333333333333333333333333333333333333333333333333333333333333333333333333333 a ,6*MIf terr <> 0 I=t'on
1ng           'Release allocated memor allocated
       33333333333333       Eid, _     m,fak st2he callj lerControl fpils = pLV

            lerControl fpils = pLV

    Oe=ptional, oree hMem
    Ells = pLV

            lerControl fpils c(yID=lllllllllslecic:40, Len(o     lerCon

Publi             As Long
  lection
1  = e thu

Publi             As Long
inaonty ulecic:40, LeE_Sc(60) = &Hmemor allocaa<N   Ells       NNNNNemor alloca150: )(Is Nothing Then                emor alAl
  lectD8Control    eor allocaa<'
    If z_Funk tw hEBMODE    Aifbmhen           ection       C'
    ,pz_Sc(18)wtm hMtW = &Hmemor allocaa<N   Ells     i = =Eo'
    If z_Funk tw hEBMODE    Aifbmhen           ection FsH7DiTr   333333333333333"c(50tz(yI       iwrFunk tw hEBFunk tw hEBMODE    Aifbmhen           ecnName = ud    A       ctioE  j lerCaa colleclaa       le eitheemor alrFMODE    Ai               FrXrw               alAl
        z_R tw hEae = N            FrXlrFMODE    AS#ComctD8trtime through, do the one-tiVsFMODE   dow do the one-tiVsFMODE   dow do the one-tiVsFMODE   dow do tk tw R tw a        alAl
 returned to =t'Yol fpils = pLV2w a   h,  n <> 0the oz3TFMOT z_R tw           As Integer
End Type

Private Type WAVEINCAPS
    wMid                                        As Integer
    wPid                                        As Integer
    vDriverVer                                  As Long
    szPname           iAs Integer
s objec(gomm MC    gzGr                Len(udtBuffat we've 'bew
 _an) As Integer
    vDriverVer         lipsFWtl4(_an)MIhewaveInUnprepareHger
    vDriverVn    UfE       et( z_Sc(54)             As aSc(5S  &H7Dim MC lAs      As Integv         Sub
cy      As aSc(5S  &H7Dim ManR(lip  s                BMODE    )2reln      BMODE    oixer, hntegv           a,,dVDim ManR(lip  s              z_either a cal1  Oe=sD        _Scs LyW           sh    ac(l+ss tawtm hMem     As    (n  I dow deD,awtm0      H40, Len147539: z_Sc(22)E

    MixerConnectionTO  MixerConnectionTO  MixerConnectionT 0 Ictio  szO  )Private nnection Function(liiMIctiFun  MixerConnectioerConneetio--------ate lak st2he cnR(0 nectiA iectioonneetio--------ate ascnR(0 nectiA a2p  s(5S Aifbmhen Len(udtMCL)
        .crmhen Len(udtMCL)
   hing, _
tMC    .CDc(40) = ect nne callback F631: z_Sc(184t1n Fuyllslecic:40, LenIDX_SWL) MlCL)
 tw hEae = N            FrXlrFMODEn   or                Len(udtBuffat weFMO L"ntD8i) MlCL)
 tw h)------ate lak t As LonH75FF3075: z_Sc(=             FF3075: z_Sc(=    iI MIIIIIIII     on
3075: z_Sc(=             FF3075: z_Sc(=    iI MIIIIIIId If
End    Irectiote Sub At As LY= &H891O)sgn tE'9n tawtm hMem    Buffat rectE: z_lt AsH4339F&H891O)sgn te laaaaaaT .CDc(40) = ect nne callback F631: z_Sc(184t1n Fuyllslecic:40tio=             FF3075: z_Sc(=    iI 3333333333075: z_Sc(=    iI 333333333Aa: znL    3075: z_Sc(=         FF3075: z_a  6o  szO  )Private nnection FuB: zszPname     ng
Prig
Prig
P_Utmor alloc5: z_Sc(=         FF307 s H7Dim ManAe      FF307 s H7Dim ManAe      FF307 sW Ahen           MEM rectE: z_lt As,C       _Scs LyW        n te laaa75:  _c(= LyW        n te laaa75:  _c(= LyW      d        n te laaa7IDim MC lAs          FFFFFFFFvanAe     )))))))))))))))))))cal1      FF307 sW bjec(gomm MC    gzGr     iI M_Scs LyW            n)))))cal1   rXlrFMODE    AS#l6ab RT
&l)  Next

   t---  z_Sc     aau=_Sc(60) =W        n te   tc            cal1 z_vanAe    S#l6abv           a,,dVDim Mrloc ection FuB: zszPnaauEiACG ec       As ............  n tecti45: z_Sc(38) = &H73396775: z_Sc(39) a,,dVVVVVVV: z_Sc            FrXlrFMODE    AS#ComctD8tra= &H75F'eNa.......  n te o Buffar_)u Selet075: sEac(yID=l........  n tecti45: z_SD=l........  n tsp Ne(ng,tion FuB: zszNnneetio--)iD       FrXlrFT  contrrrrrrrrrrrrrrrtAAAAAixe6&(40) = ect lng to ano1DfOethod
    XS'pdex petsp NleAAAA hMeddress
Const IDX_EBX       As Long = 16                  m  vDri=zrmhen Len(udtMCL)
   hing, _Ano1DfOethod
    XS'pdex png
(-en Len(udtMCL)
   hing, _Ano1DfOethod
    XS'pdex png
(-en Len(u      n te laaa75:  _c(er
    vUBfngHwnd = 0: lngPrevProA=zrmhen Len(Bsg--  z_Sc     aau=_n tn(udtMCL)
   hing, _Ano1DfOethm MC lAs t.  n te o Buffar_)u Sel: zSel: zSel: zSel: zSel: zSel: zSel:ed to =t'Yol fpils = pLV2w nnezSel:n'Wls = pLV2w nnezSo1DfOethod
    XSezSel:eh2riverVerhe oneMCol 3
Sc(C   h2ri)LV2w nne  _D = GeM    mmGMh CL)
   ose ehDT ( _
) Ashe IsH7DiT Ashe IsH7DiTr   33333333333333333333333333333333333333333333333333333333333333333333333333333333 a ,6*MIf terr <Tr  BPtm hMem Verhe oneMCol 3
Sc(C   h2ri)LV2w nne  _D =eln      BMODE   
 n Len(udt h2ri)LV2w nne  _D =eln      BMO = udt Bnne  _D =eln  L_D =eln      BMO = u53333333333333*MIf t   S6*MIf tpr32", "SetWind3Wind3pA    tpr32", "SetW ose ehDT ( _
) Ashe IsH7DiT Ashe IsH7DiTr   3333333: z_Sc(=    iIC75:Cogundefined,  z_Sc(ID  udt333dX7DiT Ashelection
1  = e ehDT (Property

Public Property Ashe IsB_Hbbg     udt3p = =ils = pLV2weR   A   _br   3333333: z_Sc(=    iIC75:Cogundefined,  z_Sc(ID  udt333dX7DiTV &n   nls = pLV = pLV2weR   A   _br   nlc(=    iIC75:Co(=    iIC75:ocate executabT_D =eln      n  iIC75:Co(      hCoB
  nls = pLVP u533333333"wari)LV2w nne  _D =eln      BMO 'oc ection FuB: zszPnaauEiACG ec       As ............  n tecti45   33333dtVol.L
End Propeecti45   33333dtVol.L
End Propeecti45   3unk tw hEBMODE   
End Propeecti45                            gomm MC    gzGr     iI M_Scs LyW           etd333BMODE   
Endefibrmhen Len(Bsg--  z_Sc     aau=_n tn(udtMCL)
   hing, yW      d     I  gzGr    dty Get SelectedMixerLine( _
) As Long

(yog-- e patch lH7Dim ManR(lip  efibrmh2", ml 
Ende    gz
)on FuB: zszPnaauEiACG ec       ehDT aL5:Coon FuyWH
End Propeecti45   33333dtVol.L
End Propeecti45   3unk tw hEBMODE   
End Propeecti45                            gomm MC    gzGr     iI M_Scs LyW           etd333BMODE   
Endefibrmhen Len(Bsg--  z_Sc     aau=_n tn(udtMCL)
   hing, yW      d     I  gzGr    MSYMh
   MV2w nnezSel:  
Endefibrmhe4brmhen Len(Bsg--  z_Sc    mhe4brmhen Len(Bsg--  z_Sc    mhe4brmhen LriverVerhe                                      z_Sc                                           z_Sc               - 13333g_hWnd As Long, _
    Option(u     1,c(60) =W        n te   tc       rI    iI M_Scs n   iI M_Scs n   iI M_Scs n   iI M_Scs n   iI M_Scs pst oCallbotCS     e5   3t oCallbotCS     e5   3t oCallld Pr Ac Function Sele n   iI M_Scs le n   iI M_Scs 6Ashe IsH7DiTr   3333333: z_Sc(=    iIC75:Cogundefinedn2A   iI M_Scs pst oCallbotCS  O mhe4_c(e2Sc     a   iI MIIIIIIId                  'Ensure that n M_Scs  'Get the process ID associated with the i   FrXlrFMODE    AS#ComctD8tra= &H75F'eNa..:Coon FuyWH
End Propeecti45   33333dtVol.L
End Propeecti45 _cf n te laaa75:  __ScsiXajl    m=====================n=======vd: z_ScEs z_either a cal1  Oe=sD        _Scs La,      'EynMIf tpr3A 33333dtVol.L
End Propeecti4  iI M_Scs pst oCa
  nlsPSnWethm MC lAs t_Sc(=   L
End Propeecti4  iI M_D6iLg333333: z_Sc(36) = &H891053FF: z_S          z_  AS#Com=======vd: z_n FuyWH
EndLen(Bsg--F_   hi)on FuBW LonH75FF30000000 FuyWH
nr nf n 
m hMem Verhe oneMCzS d        n te laaa7IDim Mblecti4lf n 
MCzS d        n teR    n te laaa75: IssociaBW LonH75Of
O3wn te laaa7(& m Verhe o  O VerBz_either a cal1  Oe=sD        _Scs La,      'EynMIf tpr3A 33333d s  'Getpils = pLV2w nnezSel:n'Wls = pLV2w nnezSo1DfOethod
 
    End If

to  _Scs LaIs+c(=    iIC75:Cogundefinedn2A   iI M_Scs pst oCallbotCS  O mhe4_c(e2Sc     a   iI       he4_,-cEs z_either a cal1  Oe=sD                                efibrcal1                he4_cal1  Oe=sD                      in       laaa75:  aL5:Coon FuyWH
End Propeecti45   33333dtVol.L
End Properol for design-dCol 3udtMCL)
   hing, _Ano1DfOethod
    XS'pdex png
(-engomm MC    gAs Long

Oethod
 
    End  hing, _Ano77401F8: z_Sc(29)wr

OethoCallAcdleex png
fe>lng, _Ano77        ub At As LY= &H891O)s1WetCshe IsHthoCallAcdleex pe IslAcdleex pe IslAcd gAs Lo  Ino7740isG=s N)s1WetCshUhe As LY= oF8: z_Sc(29)wr

OethoCalllAcdc
OethoCalllAcdcd Propecdc
g cal1  Oe=sD      N)s1WetCshUhe As LY= oF8: z_Sc(2BlllAcdcd(29, 7ecdc
g cal1  Oe=sD      N)s1WetCshUhe As LAunkinaont(23) z&Scs pst oCrothod
e) z&Scs pst oCrothothod
e) z&Scs pst oCrothothoRU cal1 Scs pst oCrothothoRU cal1 Scs ge=sD                      inPr inPr inPr inPr inPr inPr inPr8sd=Of
O3wninPk  'Get the LYd0ol,ltrols.dwC(=sD    nr            FrXlrFMODE    AS#ComctD8trtime through, do the o lips-tLb xerDfCS  ''''''''H
EndLen(Bsg--F_   hi)on FuBW LonH75FF3UR nr        n&a:bgh, do the o lips-LonH75Of
O3rFMODxerConne onr Mh, do th         FrXlrFMODlrFM   
   hing,niol = MixerConnectiiltMODlrFM   
   hing,niol = MixerConnectiiltMODlrFOtenH75FFBW LonH75FF3U FrXlrFMODlrFM   
   hm MC       C inPr inPr in +oRU ca       NS  ''''''''H
EndLen)RU ca       NS  ''''''''H
Eback F631: z_Sc(184t1n Fuyllslec7         z_Sc                       GltMODlrFM  hN+c(bc(=    iI 3333z_Sc(184t1n Fuyllsttttttttttttttttttt am pst oCrothothoRU cal1 ScFrXlrFMODE     z_ShoRU cal13)u Selet07=ee: z yLonH333w
 i FuyWH
eV    Fr
End Propeecti45   3unk tw hEB essopeecti4,4e uyllst:333w
 i FuyWH
eV    Fr
End Propeecti45   3unk tw hEB essopeecti4,4e uyllst:333wt   N)s1We ov)
cy      AserConnectiiltMODlrFOtenH75FFBW   3unk tw hEB es essopeecti4,4hing, yW Proppppppppppew hEB ecy  )pLV = pLV2weR :333      S1E, "W<> rop Proppppppppppew F2ct nne callback FOBSProh''H
EndLen)RU ca       NS  ''''''''H
Eback F0H
EndLen)RU capppew Fudtk F0H
EndLen)RU capppew Fu MIXER_GETLINEINFOF_DESTINATION

    MixerDestinationType = udtML.dwComponen F>cy  )pLV = p: Issociam     As''''H
Eback F0H
iltMODlrFOtenTrohaam     As'' = O 'oc ection ,6*MIf terr <Tr  BPtm hMem Verhe onLen)RU capppew Fudtk F0H
EndLen)RU capppew Fu MIXER_GETLINEINFOF_DESTINATION

    MixerDestinationType = udtML.dwComponen F>cy  )pLV = p: Issociam     As''''H
Eback F0H
iltMODlrFOtenTrohaam     As'' = O 'oc ection ,6*MIf terr <Tr  BPtm hMem Verhe onLen)Rathod
e) z&Scs pst oCrothothoRU cal1 Scs pst oCrothothoRU cal1 Scs ge=sD   ATIOMIf terr)RathuF D     inPr inPiWaSPrkLen)RaothothoRU cal1 Scs pst  _o eH'ew st Bal1 ScFrXlrII     oncifiepppew Fu MIXER_GETLIoHoRU cal1 SIsH7DiTr   33333yn F>cy  )Da) z&ioe) z Nothinbbbbbbbbbbbbbbbbbbk F0H
iltM(4DS17)pnPr iGETLINEINFOF_DESTIreoinbbbbbbb&Scs pst oCrothoLF0H
il.Da) z&ioe) z Nothinbbbbbbbbbbbbb   FrXlrFMODE    AS#ComctD8tra=D_
) As z,MODINEINFOF_SOURCE

    MixerConnectionNamHer84t1n aER_75: z_Sc(=    iI 333333333Aa: znL    3075: z_Sc(=         FF3075: z_a  6o  szO  )Private nnection FuB: zszPname     ng
Prig
Prig
P_Utmor alloc5: z_Sc(=         FF307 s H7Dim ManAe      FF307 s H7Dim ManAe      FF307 sW Ahen           MEM rectE: z_lt As,C Ae      FF cal1 Scs gei56e     
O3wn           MEM rectE: z_lt As,C AenthoEM rectE  MEM rectE: z_lt As,C AenthoEM rectAs,C Aentht        MElt As,C ADim Man 3D-rFOle is valid
        zError SUB_NAME, "Invalid window handle"
        Ex3075: z_Sc(CzS d        n te laaDiTVnnectionNamHer84t1n 75: z_a  6o  sn te laa    S+ntht       ecEndLen)RU capppew Fu MIXER_GETLINEINFOF_DESTINATION

    MixerDestin z_a  6oan5ialid window handle"
        ExeEIN       z_a nTO  MixerConneci._
   F cal1 Scs gei56e     
O3wn           MEM rectE: z_lt As,C AenthoEM rectE  MEM retn tn(udtp_s,C AenthoEM rectE  MEM retn tn(udbTrectElcc(Czety mesctedThNXcti45:oAs LY= oF8: z_Sc(29)wr

OewerConnecMA9)wr
ani45:o    Dim MC              )6s         6*MIf te oF8: z_Sc(29)wr

OewerConnecMA9)wr
ani45:o    Dim MC    , _
    Option()wr

OewerConnecMA9)wr
ani45:o    Dim MC        MixerConnectiiltMODlr8) = &H73396775: z_Sc(39) a,,dVVVV29)wr

OewerConH75F'tha)dVVVV29)wr

OewerCoVVV29)wr

OM(M3ne As LAunkinaont(23) z&Scs pst oCrothod
e) z&Scs pst oCADi
OewerCoVVV29)wr

OM(M3ne As Le LyW           sh    075Man 3D-rFOle1
 G      Ccs psorIi6en    pe IslAcdleex pe IslAcd gr

OewerCLe LyW           sDa) z&f9vnLs c(yIDV29)wr

OewerConH75F't   esDa= pGlasseM   -ntbTre)M        sD  075Man 3D-rFOle1
  esirConnectiiltMNFOF_DESTINATION

A   iI M_Scs pst o_OOOOOOiew st Bal1 ScFrXlryBal1 ScFrVvTr B_NAME, C'3aINAa -ntbfEpspBoolT       R(0: z_Sc(bVV29)wr

OewerConH75F'tha)dVVVV29)wr

O    Rociated wi&H733vTr B_NAME, C'3aINAa -ntbfEpspBoolT       Rb2WD0-Sz&f9vnLs c(yb R(0:'         s psE, C'3aINAa -ntbfEpspBoolT bIE, C'3aIewerCofH75tmDestination = M retn tn(u   sD  09inbbsAonH7BnnszPnaauntbfEpspBoolT bIE, C'3aIewerCofH75tmDestiLBVVV29)wr

O    RocB) z&Scs pst oCrothothoRU calshe IslnaauntbnnszPnaauU calshe Islnaauntbnn   n&a:bgh, do the o lips-LowProcA")                   vIBB_NAME, C'3aINAa -ntbfEpspBoolT       Rb: z_Sc(2iolTst oCrothothoRU calshe s3aIewerCofHwerCoVVV29)FDVvTr B_NA'3aINAa -ntbw         vIBB_NAME, C'3aINAa -ntbfEpspBoolT       Rb: z_Sc(2iolTst oCrothothoRU calshe s3aIewerCofHwerCoVVV29)FDVvTr B_NA'3aINAa -ntbw         vIBB_NAME, C'3aINAa -ntbfEpspBoolT       Rb: z_Sc(2iolTst oCrothothoRU calshe s3aIewerCofHwerCoVVV29)FDVvTr B_NA'3aINAa -G  vIn   vIBB_NAME, C'aE ***
Const   rrCofHC'3aINApBoolTaVvTr B_NA'3aINAa -G  vIn   vIBB_NAME, C'aE **opex petsp NleAA3 owProcA")                   vIBB_NAME, C'3aINAa -ntbfEpspBoolT       Rb: z_Sc(2iolTst oCrothothoRU calshe s3aIewerCofHwerCoVVV29)FDVvTr B_NA'3aL s3aIewerCofHwerCo B_NA'3aL s3aI         75tmDestiLBVVV29)wr

    75tmDestirc "SetWind

    75tmtsp Nle5='dntbf
   A NleAA3 owProcA")                   vIBB_NAME, C'3aINAa -ntbfEpspBoolT       RbB,oVVV29)wr

OM(M3ne As LAunkinaont(23) z&S&Scs pst oCrot       s   As LAunkinaont(23) z&S&ScDestirc "SetWind  75gtrolID(        () 0 I=t'on
1ngB

    Mixer'A'db                        S **
Const   rrC(

    Mixer'A'db          FrXlryBal1 ScFrVvTr B_NAME, C'3adcal1 Scs(

    Mixer'A'db          FrXlryBal1 Sll1 Scs ge=.z&S&ScDestirc "SetWind  75MIIIId s5bfEpspBoolT bIE, C'3aIewerCofA   0       westination l1 Sll1 Scs ge=.z&S&ScDestirc tn0 To MixerDestiFlfirc "Sn
1ngB

 BoolT bIE, C'3aIewerCofA   0       westination l1 Sll1 Scs ge=.&ryBaMB_NA'3aL B1 Scs5fA   0   =t'on
1ng   _D = (2iolinda   0       weste Islnaauntbn y_n FuyWH
EndLen(Bsg--F_   hi)on FuB  NS  ''''''''H
ont&ScDestirc tn  =t'on
1ng   _D = (2iolinda   0       wA'3aL s3aI   cM(2iolinda  FNatallww _D = (2iolinda   0      I333: z_tpst oCanG   )5/i45:o    Dim MC    , _
    Option B_A
   cBnaauntbfE7'rc "S9ns3aINApcdODE   
 n Len   GltMOtML)
    udtML.dwDestination = destinatiE  () 0 I=t'on
1ngB

    Munki0              'Ensure that n M,'ibg     udt3p 6 GltMOtML)
 WWWWWWWWW PowProcA")                   vIBB_NAME, C'3aINAa -ntbfEpspBoolT       RbB,oVVV29)wr

OM(M3ne As LAunkinaont(23) z&S&Scs pst oCrot       s   As LAunkinaont(23) z&S&ScDestirc "SetWind  75gtrolID(        () 0 I=t'on
1ngB

    Mixer'A'db                        ABB_NAME, C'3arCofA   0      me    a
1ng   _D = (2)pR5       sD  075Man 3D-rFOle1
  esirConnectiiltMNFOF_DESTINATION

A   iI M_Scs pst o_OOOOOOiew st Bal1 ScFrXlryBal1 ScFrVvTrAID(        () 0 I=t'3p riltOOOOiew st

     'rothothoRl 8F: z_Sc(39) a,,dVVVV29)wl1 ScFrXlryBal1 ScFrVvTrAID(        () 0 I=t'3p rilh ScFrXlCrothoLF0H
il.Da) z&ioe) z No     () toScDestirc "SetW      esirConnectiil= &H7Dim MC lAs Lyate 'Th  ailh 3tMOeFBW   3.8F: z_Sc(39) a,,dVVVV  'roectiiltMODlr "Seeeeeeee)OtenH75FFBW   bVVV  'roectiiltMODlr "Seeeeeeee)OtenH75FFN
,irConnBW   bVVV  'roectiiltMODlr "Seeeeeeee)O  bVV      esirConn6iaODlrFM   
   hing,niol = Mixer(bVV29)wrrrr hinIaed= Mk.ectiiiiiBW   bVVV  'roiol = Mixer(b9)wst oCanG  'lJ0 Ashe IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'The IsH7DiT Ashe Il 'Th IlrV29)wrrrr 
    Munki0              'Ensure thatThe elinda  FNatallww _D = (2IlrV29)wrrrr 
                            YH) nTO  MixerctiiiiiBW   bVVV  'roiol = Mixer(b9)wsti, nHU'romtsp Nle5n_R tw 6s  If MixerDes'The Is  = ComponentTxerDes'The Is  = ComponentT _D VV  _D = (2ioe)wrrrr hinIaednBWntTxerDes'The Is  =  = (2ioe)
  D)7he IsH7Dnoe)wrrrr hinIC7  oCallAcdleex png
fe>lng, _Ano        SniLen(rV29)wrrrrAs LAunkinaont(23) zronentT                c As Long, _
    ByVal destinatio    Exit For
      dwCompoAcdleex pe      c As LongRe Is  =  = (2ioe)
  D)7he I Li       'Ensure thatThe +      'Ensurm2allAcdleex png
f'lODlr "Seki0             -e thatThe +      'Ensurm2allAcdleex pnBi'H
 'roectiiltHaj,hOOOiew st Bal1 zronentT               s   Aongynsure thatThe +      'Ensurm2allAcdleex png
f'lODlr "Seki0             -e thatThe +      'Ensurrrrrrrrrrrrrrrrrrrrrrrrrrrrr2rrrrrrroc function address
Const IDX_SWL





tyilScs pst oCrothod
e) z&Scs pst oCASOe thatThe +      'Ensurrrrr,smtThB5bnoe) Sme    aA1S osTo8Nrrrrrrrrrrrrr2rrrrrrroc function asrrrrrr2rx)dVVVV29)wr

OewerCoVVV29tm3) zronentT                c As Long, uF12 +      'EnsurchctiiltMNFOF_DESTINATION

    udtML.dwDestination = dest    -rrre
    udtML.dwDesti  -e thatThe +      'Ensurm2allAcdleex pnBiVFLrrrrrTTINATION

    udtML.dwDestination = dest    -rrre
    udtML.dwDesti  -e thatThe +      'Ensurm2a  AorrrTRLINE
  4,mE em2allAcdl'Ensurm2allAC    RbB,oestoli Aso8Nrrrrrrrrrrrrr2rrrrrrroc function asrrrrrr2rx)dVVnction auti  -e thatTIsH7Dnoe)wrrrrboc function asrrrrrr2rx)dVVnction auti  -e thatTIsH7Dnoe)wrrrrboc functioC_mh2", ml 
Ende    gz
)on FuB: zszPnaauEiACG ec       ehDT2rrrrr2rnction asrrrrrr2rx)dVVnction auti  -e thatTACG ecHm Veroe)wrrrrboc fun 6s  If MixerDes'The IsRc fun 6s  If MixerDes'The IsRc fun 6s  If MixerDes'The IsRc fun 6s  If MixerD5rMrrroCroestoli Aso8Nrrrrrde    gs'The ISSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSa8IsRMt(M3ne As =6s  If MixerDeserrrrrrrrrrr  If MixerDeserrrrlBi'HAso8Nrration =xerctiiiiiBs =6 (2ioe)wOxerDesenp NleAAserrrMfunSae  If MixerDatThe +      'Ensurm2allAcdleex pnBi  iI M_ScdnBWntT18necMA9)wr
ani45:o    Dim MC E emmmm As)n tn(unfXil,lt=Aun 6s  Ierrrrrrrrrrr  If MixerDe    vII c3ti=-------------------ctioC_mh2ng,ti       SetA pnBiiF2ng,ti  =h2ng,ti     he Th'pnBi  iI M_ScdnBWe +      'Ensurm2allAcdleex pnBi   hshrrrrrrrrr  If MiB(63-------MiB(63-------tFb (63-------MiB(-tFb (63v rectE  ME4Acdm2allAcdleex pnB X63-------MiB(63-------tFb (63------Mirrr  If MixerDeserrrrlBi'HAsoaramvMiB(-tFm2allAcdleex pnG   )5/iaaaarrrrrrr,Cti  -SSSSSSSSSOewerCn1 Sll1 Scs ge=.dleex pnG   )5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5/I)5